#ifndef CLASS_H
#define CLASS_H
#include "Object.h"
#include "Type.h"
#include "Image.h"
#include <string>
#include <list>
#include <map>
#include <set>
using namespace std;
#define FIELD_ORDINARY 0

class ClassField{
   public:
   string name;
   Type* type;
   int sizeOverride;
   int offset;
   unsigned customObject:1;
};

class Class:public Object{
    friend class Object;
    friend Object* primitive_class_set_parent(Image* image,Object* self,int argc,Object** argv);
    friend Object* primitive_class_initialize(Image* image,Object* self,int argc,Object** argv);
    friend Class* classCls(Image* image);
   public:
      int getSize();
      void addCustomField(string name,int size);
      void addField(string name,Type* type,int flags);
      void addMethod(Method* m);
      void setParent(Class* cls);
      //accesing instances
      Method* findMethod(string selector);
      Object* newInstance(bool call=true);
      Object* sendClass(Object* self,string selector,int argc,Object** argv);
      Object* get(Object* obj,string field);
      void set(Object* obj,string field,Object* value);
      bool hasField(string field);
      bool hasDirectlyDefined(string method);
      void initializeObject(Object* o,bool callInitMethod=true);
      void setFinal(bool final);
      bool isFinal();
      void setName(string name);
      string getName();
   private:
       Class();
      Image* image;
      bool wasAlreadyNamed;
      string name;
      void recomputeSize();
      void genVPTR(bool shouldDelete);
      //inheritance
      Class* parentClass;
      bool final;
      std::set<Class*> subclasses;
      //structure
      list<ClassField*> structure;
      map<string,ClassField*> fields;
      int size;
      //methods
      list<Method*> methods;
      map<string,Method*> selectors;
   protected:   
      VPTR clsVptr;
};
#endif

Object* primitive_class_set_parent(Image* image,Object* self,int argc,Object** argv);
Object* primitive_class_set_name(Image* image,Object* self,int argc,Object** argv);
Object* primitive_class_add_method(Image* image,Object* self,int argc,Object** argv);
Object* primitive_class_initialize(Image* image,Object* self,int argc,Object** argv);
Object* primitive_class_new(Image* image,Object* self,int argc,Object** argv);
Object* primitive_class_add_field(Image* image,Object* self,int argc,Object** argv);